home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d8 / pdriver5.arc / WD8003E.ASM < prev    next >
Assembly Source File  |  1989-12-17  |  28KB  |  862 lines

  1. version    equ    4
  2.  
  3.     include    defs.asm
  4.  
  5. ;   PC/FTP Packet Driver source, conforming to version 1.05 of the spec
  6. ;   Updated to version 1.08 Feb. 17, 1989 by Russell Nelson.
  7. ;   Robert C Clements, K1BC,  August 19, 1988
  8. ;   Portions (C) Copyright 1988 Robert C Clements
  9.  
  10. ;   Version 3 updated by Jan Engvald LDC to handle WD8003ET/A (micro channel
  11. ;   card) and to utilize all 32 kbyte memory on the WD8003EBT card.
  12.  
  13. ;   This program is free software; you can redistribute it and/or modify
  14. ;   it under the terms of the GNU General Public License as published by
  15. ;   the Free Software Foundation, version 1.
  16. ;
  17. ;   This program is distributed in the hope that it will be useful,
  18. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. ;   GNU General Public License for more details.
  21. ;
  22. ;   You should have received a copy of the GNU General Public License
  23. ;   along with this program; if not, write to the Free Software
  24. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. code    segment    byte public
  27.     assume    cs:code, ds:code
  28.  
  29. ; Stuff specific to the Western Digital WD003E Ethernet controller board
  30. ; C version by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
  31. ; Symbol prefix "EW" is for Ethernet, Western-digital card
  32.  
  33. ; The EW registers - First, the board registers */
  34.  
  35. EW_CMD        equ    000h    ; Board's command register
  36. EW_SAPROM    equ    008h    ; Window on station addr prom
  37.  
  38. ; The EW registers - Next, the DS8390 chip registers */
  39. ; There are two (really 3) pages of registers in the chip. You select
  40. ; which page you want, then address them at offsets 10-1F from base.
  41. ; The chip command register (EW_CCMD) appears in both pages.
  42.  
  43. EW_CCMD        equ    010h    ; Chip's command register
  44.  
  45. ; Page 0
  46.  
  47. EW0_STARTPG    equ    011h    ; Starting page of ring bfr
  48. EW0_STOPPG    equ    012h    ; Ending page +1 of ring bfr
  49. EW0_BOUNDARY    equ    013h    ; Boundary page of ring bfr
  50. EW0_TSR        equ    014h    ; Transmit status reg
  51. EW0_TPSR    equ    014h    ; Transmit starting page
  52. EW0_TCNTLO    equ    015h    ; Low  byte of tx byte count
  53. EW0_TCNTHI    equ    016h    ; High byte of tx byte count
  54. EW0_ISR        equ    017h    ; Interrupt status reg
  55. EW0_RCNTLO    equ    01ah    ; Remote byte count reg
  56. EW0_RCNTHI    equ    01bh    ; Remote byte count reg
  57. EW0_RXCR    equ    01ch    ; RX control reg
  58. EW0_TXCR    equ    01dh    ; TX control reg
  59. EW0_COUNTER0    equ    01dh    ; Rcv alignment error counter
  60. EW0_DCFG    equ    01eh    ; Data configuration reg
  61. EW0_COUNTER1    equ    01eh    ; Rcv CRC error counter
  62. EW0_IMR        equ    01fh    ; Interrupt mask reg
  63. EW0_COUNTER2    equ    01fh    ; Rcv missed frame error counter
  64.  
  65. ; Page 1
  66.  
  67. EW1_PHYS    equ    011h    ; This board's physical enet addr
  68. EW1_CURPAG    equ    017h    ; Current memory page
  69. EW1_MULT    equ    018h    ; Desired multicast addr
  70.  
  71.  
  72. ; Board commands in EW_CMD
  73. EW_RESET    equ    080h    ; Reset the board
  74. EW_MEMEN    equ    040h    ; Enable the shared memory
  75. EW_MEM_MASK    equ    03fh    ; B18-B13 of address of the shared memory
  76.  
  77. ; Chip commands in EW_CCMD
  78. EWC_STOP    equ    001h    ; Stop the chip
  79. EWC_START    equ    002h    ; Start the chip
  80. EWC_TRANS    equ    004h    ; Transmit a frame
  81. EWC_NODMA    equ    020h    ; No remote DMA used on this card
  82. EWC_PAGE0    equ    000h    ; Select page 0 of chip registers
  83. EWC_PAGE1    equ    040h    ; Select page 1 of chip registers
  84.  
  85. ; Commands for RX control reg
  86. EWRXCR_MON    equ    020h    ; Monitor mode
  87. EWRXCR_BCST    equ    004h    ; Accept broadcasts
  88.  
  89. ; Commands for TX control reg
  90. EWTXCR_LOOP    equ    002h    ; Set loopback mode
  91.  
  92. ; Bits in EW0_DCFG - Data config register
  93. EWDCFG_BM8    equ    048h    ; Set burst mode, 8 deep FIFO
  94. EWDCFG_WTS    equ    1    ; Word Transfer Select
  95.  
  96. ; Bits in EW0_ISR - Interrupt status register
  97. EWISR_RX    equ    001h    ; Receiver, no error
  98. EWISR_TX    equ    002h    ; Transmitter, no error
  99. EWISR_RX_ERR    equ    004h    ; Receiver, with error
  100. EWISR_TX_ERR    equ    008h    ;    Transmitter, with error
  101. EWISR_OVER    equ    010h    ; Receiver overwrote the ring
  102. EWISR_COUNTERS    equ    020h    ; Counters need emptying
  103. EWISR_RESET    equ    080h    ; Reset completed
  104. EWISR_ALL    equ    01fh    ; Interrupts we will enable
  105.  
  106. ; Bits in received packet status byte and EW0_RSR
  107. EWPS_RXOK    equ    001h    ; Received a good packet
  108.  
  109. ; Bits in TX status reg
  110.  
  111. EWTSR_COLL    equ    004h    ; Collided at least once
  112. EWTSR_COLL16    equ    008h    ; Collided 16 times and was dropped
  113. EWTSR_FU    equ    020h    ; TX FIFO Underrun
  114.  
  115. ; Shared memory management parameters
  116.  
  117. XMIT_MTU    equ    600h    ; Largest packet we have room for.
  118. SM_TSTART_PG    equ    0    ; First page of TX buffer
  119. SM_RSTART_PG    equ    6    ; Starting page of ring
  120. SM_BASE        equ    0C400h    ; Default para where shared memory starts
  121.                 ; Real value set at attach time.
  122.  
  123. ; Description of header of each packet in receive area of shared memory
  124.  
  125. EW_RBUF_STAT    equ    0    ; Received frame status
  126. EW_RBUF_NXT_PG    equ    1    ; Page after this frame
  127. EW_RBUF_SIZE    equ    2    ; Length of this frame (word access)
  128. EW_RBUF_SIZE_LO    equ    2    ; Length of this frame
  129. EW_RBUF_SIZE_HI    equ    3    ; Length of this frame
  130. EW_RBUF_NHDR    equ    4    ; Length of above header area
  131.  
  132. ; End of WD8003E parameter definitions
  133.  
  134. ; The following three values may be overridden from the command line.
  135. ; If they are omitted from the command line, these defaults are used.
  136.  
  137.     public    int_no, io_addr, mem_base
  138. int_no        db    3,0,0,0        ; Interrupt level
  139. io_addr        dw    0280h,0        ; I/O address for card (jumpers)
  140. mem_base    dw    0c400h,0    ; Shared memory addr (software)
  141.  
  142.     public    driver_class, driver_type, driver_name
  143. driver_class    db    1        ;from the packet spec
  144. driver_type    db    14        ;from the packet spec
  145. driver_name    db    'WD8003E',0    ;name of the driver.
  146.  
  147.     public    rcv_modes
  148. rcv_modes    dw    4        ;number of receive modes in our table.
  149.         dw    0,0,0,rcv_mode_3
  150.  
  151. SM_RSTOP_PG    db    32        ; Last page +1 of ring
  152.     extrn    sys_features: byte
  153. microchannel    equ    2        ; flag in above byte
  154. ; send_pkt: - The Transmit Frame routine
  155.  
  156.     public    send_pkt
  157. send_pkt:
  158. ;enter with ds:si -> packet, cx = packet length.
  159. ;exit with nc if ok, or else cy if error, dh set to error number.
  160.     assume    ds:nothing
  161.     loadport        ; Point at chip command register
  162.     setport EW_CCMD        ; ..
  163.     mov bx,    8000h        ; Avoid infinite loop
  164. tx_wait:
  165.     in al,    dx        ; Get chip command state
  166.     test al,EWC_TRANS    ; Is transmitter still running?
  167.     jz    tx_idle        ; Go if free
  168.     dec    bx        ; Count the timeout
  169.     jnz    tx_wait        ; Fall thru if TX is stuck
  170.                 ; Should count these error timeouts
  171.                 ; Maybe need to add recovery logic here
  172. tx_idle:
  173.     cmp    cx,XMIT_MTU    ; Is this packet too large?
  174.     ja    send_pkt_toobig
  175.  
  176.     cmp cx,    RUNT        ; Is the frame long enough?
  177.     jnb    tx_oklen    ; Go if OK
  178.     mov cx,    RUNT        ; Stretch frame to minimum allowed
  179. tx_oklen:
  180.     push    cx        ; Hold count for later
  181.                 ; Now compute destination of move in es:di
  182.     mov ax,    mem_base    ; Compute base of transmit buffer
  183. ;    add ax,    SM_TSTART_PG*16    ; The right page in mem (currently zero)
  184.     mov es,    ax        ; Paragraph of the TX buffer
  185.     xor di,    di        ; Fill starting at beginning of paragraph
  186. ; Can't use movemem which word aligns to the source, but needs to word
  187. ; align to the destination writing to WD8003ET/A. Fortunately works for
  188. ; all cards.
  189.     inc    cx        ; if odd bytes pad to word
  190.     shr    cx,1        ; convert bytes to words
  191.     rep    movsw        ; word access required by MC card
  192.     pop    cx        ; Get back count to give to board
  193.     loadport        ; Base of I/O regs
  194.     setport    EW0_TCNTLO    ; Low byte of TX count
  195.     mov al,    cl        ; Get the count
  196.     out dx,    al        ; Tell card the count
  197.     setport    EW0_TCNTHI    ; High byte of TX count
  198.     mov al,    ch        ; Get the count
  199.     out dx,    al        ; Tell card the count
  200.     setport    EW0_TPSR    ; Transmit Page Start Register
  201.     mov al,    SM_TSTART_PG
  202.     out dx,    al        ; Start the transmitter
  203.     setport    EW_CCMD        ; Chip command reg
  204.     mov al,    EWC_TRANS+EWC_NODMA
  205.     out dx,    al        ; Start the transmitter
  206.     clc
  207.     ret            ; End of transmit-start routine
  208.  
  209. send_pkt_toobig:
  210.     mov    dh,NO_SPACE
  211.     stc
  212.     ret
  213.  
  214.  
  215.     public    get_address
  216. get_address:
  217. ;get the address of the interface.
  218. ;enter with es:di -> place to get the address, cx = size of address buffer.
  219. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  220.     assume ds:code
  221.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  222.     jb    get_addr_x    ; No, fail.
  223.     mov cx,    EADDR_LEN    ; Yes. Set count for loop
  224.     loadport        ; Base of device
  225.     setport    EW_SAPROM    ; Where the address prom is
  226.     cld            ; Make sure string mode is right
  227. get_addr_loop:
  228.     in al,    dx        ; Get a byte of address
  229.     stosb            ; Feed it to caller
  230.     inc    dx        ; Next byte at next I/O port
  231.     loop    get_addr_loop    ; Loop over six bytes
  232.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  233.     clc            ; Carry off says success
  234.     ret
  235. get_addr_x:
  236.     stc            ; Tell caller our addr is too big for him
  237.     ret
  238.  
  239.  
  240.     public    set_address
  241. set_address:
  242.     assume    ds:nothing
  243. ;enter with ds:si -> Ethernet address, CX = length of address.
  244. ;exit with nc if okay, or cy, dh=error if any errors.
  245. ;
  246.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  247.     je    set_address_4
  248.     mov    dh,BAD_ADDRESS
  249.     stc
  250.     jmp    short set_address_done
  251. set_address_4:
  252.  
  253.     loadport
  254.     setport    EW1_PHYS
  255. set_address_1:
  256.     lodsb
  257.     out    dx,al
  258.     inc    dx
  259.     loop    set_address_1
  260.  
  261. set_address_okay:
  262.     mov    cx,EADDR_LEN        ;return their address length.
  263.     clc
  264. set_address_done:
  265.     push    cs
  266.     pop    ds
  267.     assume    ds:code
  268.     ret
  269.  
  270.  
  271. rcv_mode_3:
  272. ;receive mode 3 is the only one we support, so we don't have to do anything.
  273.     ret
  274.  
  275.  
  276.     public    set_multicast_list
  277. set_multicast_list:
  278. ;enter with es:di ->list of multicast addresses, cx = number of bytes.
  279. ;return nc if we set all of them, or cy,dh=error if we didn't.
  280.     mov    dh,NO_MULTICAST
  281.     stc
  282.     ret
  283.  
  284.  
  285.     public    get_multicast_list
  286. get_multicast_list:
  287. ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
  288. ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
  289. ;return cy, NO_MULTICAST if we don't implement multicast.
  290.     mov    dh,NO_MULTICAST
  291.     stc
  292.     ret
  293.  
  294.  
  295.     public    reset_interface
  296. reset_interface:
  297.     assume ds:code
  298.     loadport        ; Base of I/O regs
  299.     setport    EW_CCMD        ; Chip command reg
  300.     mov al,    EWC_STOP+EWC_NODMA
  301.     out dx,    al        ; Stop the DS8390
  302.     setport    EW0_ISR        ; Interrupt status reg
  303.     mov al,    0ffh        ; Clear all pending interrupts
  304.     out dx,    al        ; ..
  305.     setport    EW0_IMR        ; Interrupt mask reg
  306.     xor al,    al        ; Turn off all enables
  307.     out dx,    al        ; ..
  308.     ret
  309.  
  310.  
  311. ;called when we want to determine what to do with a received packet.
  312. ;enter with cx = packet length, es:di -> packet type.
  313. ;It returns with es:di = 0 if don't want this type or if no buffer available.
  314.     extrn    recv_find: near
  315.  
  316. ;called after we have copied the packet into the buffer.
  317. ;enter with ds:si ->the packet, cx = length of the packet.
  318.     extrn    recv_copy: near
  319.  
  320.     extrn    count_in_err: near
  321.     extrn    count_out_err: near
  322.  
  323.     public    recv
  324. recv:
  325. ;called from the recv isr.  All registers have been saved, and ds=cs.
  326. ;Actually, not just receive, but all interrupts come here.
  327. ;Upon exit, the interrupt will be acknowledged.
  328.  
  329.     assume    ds:code
  330. check_isr:            ; Was there an interrupt from this card?
  331.     loadport        ; Point at interrupt status register
  332.     setport    EW0_ISR        ; ..
  333.     in al,    dx        ; Get pending interrupts
  334.     and al,    EWISR_ALL    ; Any?
  335.     jnz    isr_test_overrun
  336.     ret            ; Go if none
  337.  
  338. ; First, a messy procedure for handling the case where the rcvr
  339. ; over-runs its ring buffer.  This is spec'ed by National for the chip.
  340. isr_test_overrun: 
  341.     test al,EWISR_OVER    ; Was there an overrun?
  342.     jnz    recv_overrun    ; Go if so.
  343.     jmp    recv_no_overrun    ; Go if not.
  344. recv_overrun:
  345.     setport    EW_CCMD        ; Stop the card
  346.     mov al,    EWC_STOP+EWC_NODMA
  347.     out dx,    al        ; Write "stop" to command register
  348.  
  349. ; Remove one frame from the ring
  350.     setport    EW0_BOUNDARY    ; Find end of this frame
  351.     in al,    dx        ; Get memory page number
  352.     inc    al        ; Page plus 1
  353.     cmp al,    SM_RSTOP_PG    ; Wrapped around ring?
  354.     jnz    rcv_ovr_nwrap    ; Go if not
  355.     mov al,    SM_RSTART_PG    ; Yes, wrap the page pointer
  356. rcv_ovr_nwrap:
  357.     xor ah,    ah        ; Convert page to segment
  358.     mov cl,    4
  359.     mov bl,    al        ; Page number as arg to rcv_frm
  360.     shl ax,    cl        ; ..
  361.     add ax,    mem_base    ; Page in this memory
  362.     mov es,    ax        ; Segment pointer to the frame header
  363.     push    es        ; Hold this frame pointer for later
  364.     mov ax,    es:[EW_RBUF_STAT]    ; Get the buffer status byte
  365.     test al,EWPS_RXOK    ; Is this frame any good?
  366.     jz    rcv_ovr_ng    ; Skip if not
  367.      call    rcv_frm        ; Yes, go accept it
  368. rcv_ovr_ng:
  369.     pop    es        ; Back to start of this frame
  370.     mov ax,    es:[EW_RBUF_NXT_PG and 0fffeh] ; Get pointer to next frame
  371.     mov    al,ah
  372.     dec    al        ; Back up one page
  373.     cmp al,    SM_RSTART_PG    ; Did it wrap?
  374.     jae    rcv_ovr_nwr2
  375.     mov al,    SM_RSTOP_PG    ; Yes, back to end of ring
  376.     dec    al
  377. rcv_ovr_nwr2:
  378.     loadport        ; Point at boundary reg
  379.     setport    EW0_BOUNDARY    ; ..
  380.     out dx,    al        ; Set the boundary
  381.     setport    EW0_RCNTLO    ; Point at byte count regs
  382.     xor al,    al        ; Clear them
  383.     out dx,    al        ; ..
  384.     setport    EW0_RCNTHI
  385.     out dx,    al
  386.     setport    EW0_ISR        ; Point at status reg
  387.     mov cx,    8000h        ; Timeout counter
  388. rcv_ovr_rst_loop:
  389.     in al,    dx        ; Is it finished resetting?
  390.     test al,EWISR_RESET    ; ..
  391.     jnz    rcv_ovr_rst    ; Go if so
  392.     dec    cx        ; Loop til reset, or til timeout
  393.     jnz    rcv_ovr_rst_loop
  394. rcv_ovr_rst:
  395.     loadport        ; Point at Transmit control reg
  396.      setport    EW0_TXCR    ; ..
  397.     mov al,    EWTXCR_LOOP    ; Put transmitter in loopback mode
  398.     out dx,    al        ; ..
  399.     setport    EW_CCMD        ; Point at Chip command reg
  400.     mov al,    EWC_START+EWC_NODMA
  401.     out dx,    al        ; Start the chip running again
  402.     setport    EW0_TXCR    ; Back to TX control reg
  403.     xor al,    al        ; Clear the loopback bit
  404.     out dx,    al        ; ..
  405.     setport    EW0_ISR        ; Point at Interrupt status register
  406.     mov al,    EWISR_OVER    ; Clear the overrun interrupt bit
  407.     out dx,    al        ; ..
  408.     call    count_in_err    ; Count the anomaly
  409.      jmp    check_isr    ; Done with the overrun case
  410.  
  411. recv_no_overrun:
  412. ; Handle receive flags, normal and with error (but not overrun).
  413.     test al,EWISR_RX+EWISR_RX_ERR    ; Frame received without overrun?
  414.     jnz    recv_frame    ; Go if so.
  415.     jmp    recv_no_frame    ; Go if not.
  416. recv_frame:
  417.     loadport        ; Point at Chip's Command Reg
  418.      setport    EW_CCMD        ; ..
  419.     mov al,    EWC_NODMA+EWC_PAGE1
  420.     out dx,    al        ; Switch to page 1 registers
  421.     setport    EW1_CURPAG    ;Get current page of rcv ring
  422.     in al,    dx        ; ..
  423.     mov ah,    al        ; Hold current page in AH
  424.      setport    EW_CCMD        ; Back to page zero registers
  425.     mov al,    EWC_NODMA+EWC_PAGE0
  426.     out dx,    al        ; Switch back to page 0 registers
  427.     setport    EW0_BOUNDARY    ;Get boundary page
  428.     in al,    dx        ; ..
  429.     inc    al        ; Step boundary from last used page
  430.     cmp al,    SM_RSTOP_PG    ; Wrap if needed
  431.     jne    rx_nwrap3    ; Go if not
  432.     mov al,    SM_RSTART_PG    ; Wrap to first RX page
  433. rx_nwrap3:
  434.     cmp al,    ah        ; Read all the frames?
  435.     je    recv_frame_break    ; Finished them all
  436.     mov bl,    al        ; Page number as arg to rcv_frm
  437.     xor ah,    ah        ; Make segment pointer to this frame
  438.     mov cl,    4        ; 16 * pages = paragraphs
  439.     shl ax,    cl        ; ..
  440.     add ax,    mem_base    ; That far into shared memory
  441.     mov es,    ax        ; Segment part of pointer
  442.     push    es        ; Hold on to this pointer for later
  443.     mov ax,    es:[EW_RBUF_STAT]    ; Get the buffer status byte
  444.     test al,EWPS_RXOK    ; Good frame?
  445.     jz    recv_no_rcv
  446.     call    rcv_frm        ; Yes, go accept it
  447. recv_no_rcv:
  448.     pop    es        ; Back to base of frame
  449.     mov ax,    es:[EW_RBUF_NXT_PG and 0fffeh] ; Start of next frame
  450.     mov    al,ah
  451.     dec    al        ; Make previous page for new boundary
  452.     cmp al,    SM_RSTART_PG    ; Wrap around the bottom?
  453.     jae    rcv_nwrap4
  454.     mov al,    SM_RSTOP_PG    ; Yes
  455.     dec    al
  456. rcv_nwrap4:
  457.     loadport        ; Point at the Boundary Reg again
  458.      setport    EW0_BOUNDARY    ; ..
  459.     out dx,    al        ; Set new boundary
  460.     jmp    recv_frame    ; See if any more frames
  461.  
  462. recv_frame_break:
  463.     loadport        ; Point at Interrupt Status Reg
  464.      setport    EW0_ISR        ; ..
  465.     mov al,    EWISR_RX+EWISR_RX_ERR+EWISR_OVER
  466.     out dx,    al        ; Clear those requests
  467.     jmp    check_isr    ; See if any other interrupts pending
  468.  
  469. recv_no_frame:                ; Handle transmit flags.
  470.     test al,EWISR_TX+EWISR_TX_ERR    ; Frame transmitted?
  471.     jnz    isr_tx        ; Go if so.
  472.     jmp    isr_no_tx    ; Go if not.
  473. isr_tx:
  474.     mov ah,    al        ; Hold interrupt status bits
  475.     loadport        ; Point at Transmit Status Reg
  476.      setport    EW0_TSR        ; ..
  477.     in al,    dx        ; ..
  478.     test ah,EWISR_TX    ; Non-error TX?
  479.     jz    isr_tx_err    ; No, do TX error completion
  480.     test al,EWTSR_COLL16    ; Jammed for 16 transmit tries?
  481.     jz    isr_tx_njam    ; Go if not
  482.     call    count_out_err    ; Yes, count those
  483. isr_tx_njam:
  484.     setport    EW0_ISR        ; Clear the TX complete flag
  485.     mov al,    EWISR_TX    ; ..
  486.     out dx,    al        ; ..    
  487.     jmp    isr_tx_done
  488. isr_tx_err:
  489.     test al,EWTSR_FU    ; FIFO Underrun?
  490.     jz    isr_txerr_nfu
  491.     call    count_out_err    ; Yes, count those
  492. isr_txerr_nfu:
  493.     loadport        ; Clear the TX error completion flag
  494.     setport    EW0_ISR        ; ..
  495.     mov al,    EWISR_TX_ERR    ; ..
  496.     out dx,    al        ; ..    
  497. isr_tx_done:
  498. ; If TX queue and/or TX shared memory ring buffer were being
  499. ; used, logic to step through them would go here.  However,
  500. ; in this version, we just clear the flags for background to notice.
  501.  
  502.      jmp    check_isr    ; See if any other interrupts on
  503.  
  504. isr_no_tx:
  505.      jmp    check_isr    ; Anything else to do?
  506.  
  507.  
  508. ; Do the work of copying out a receive frame.
  509. ; Called with bl/ the page number of the frame header in shared memory/
  510. ; Also, es/ the paragraph number of that page.
  511.  
  512. rcv_frm:
  513. ; Old version checked size, memory space, queue length here. Now done
  514. ; in higher level code.
  515. ; Set cx to length of this frame.
  516.         mov cx, es:[EW_RBUF_SIZE]       ; Extract size of frame
  517.         sub cx, EW_RBUF_NHDR            ; Less the header stuff
  518.         cmp cx, 1514
  519.         jbe rcv_size_ok                 ; is the size sane? 
  520.         cmp ch, cl                      ; is it starlan bug (dup of low byte)
  521.         jz  rcv_starlan_bug
  522.         mov cx, 1514                    ; cap the length
  523.         jmp rcv_size_ok
  524. rcv_starlan_bug:                        ; fix the starlan bug
  525.         mov ch, es:[EW_RBUF_NXT_PG]     ; Page after this frame
  526.         cmp ch, bl
  527.         ja  rcv_frm_no_wrap
  528.         add ch, SM_RSTOP_PG             ; Wrap if needed
  529.         dec ch
  530. rcv_frm_no_wrap:
  531.         sub ch, bl
  532.         dec ch
  533. rcv_size_ok:
  534. ; Set es:di to point to Ethernet type field.  es is already at base of
  535. ; page where this frame starts.  Set di after the header and two addresses.
  536.     mov di,    EW_RBUF_NHDR+EADDR_LEN+EADDR_LEN
  537.     push    bx            ; Save page number in bl
  538.     push    cx            ; Save frame size
  539.     push    es
  540.     mov ax,    cs            ; Set ds = code
  541.     mov ds,    ax
  542.     assume    ds:code
  543.     call    recv_find        ; See if type and size are wanted
  544.     pop    ds            ; RX page pointer in ds now
  545.     assume    ds:nothing
  546.     pop    cx
  547.     pop    bx
  548.     cld            ; Copies below are forward, please
  549.     mov ax,    es        ; Did recv_find give us a null pointer?
  550.     or ax,    di        ; ..
  551.     je    rcv_no_copy    ; If null, don't copy the data    
  552.  
  553.     push    cx        ; We will want the count and pointer
  554.     push    es        ;  to hand to client after copying,
  555.     push    di        ;  so save them at this point
  556.  
  557. ;; if ( (((size + 255 + EW_RBUF_NHDR) >> 8) + pg) > SM_RSTOP_PG){
  558.     mov ax,    cx        ; Length of frame
  559.     add ax,    EW_RBUF_NHDR+255 ; Including the overhead bytes, rounded up
  560.     add ah,    bl        ; Compute page with last byte of data in ah
  561.     cmp ah,    SM_RSTOP_PG    ; Over the top of the ring?
  562.     ja    rcopy_wrap    ; Yes, move in two pieces
  563.     mov si,    EW_RBUF_NHDR    ; One piece, starts here in first page (in ds)
  564.     jmp    rcopy_one_piece    ; Go move it
  565.  
  566. rcopy_wrap:
  567. ;; Copy in two pieces due to buffer wraparound. */
  568. ;; n = ((SM_RSTOP_PG - pg) << 8) - EW_RBUF_NHDR;    /* To top of mem */
  569.     mov ah,    SM_RSTOP_PG    ; Compute length of first part
  570.     sub ah,    bl        ;  as all of the pages up to wrap point
  571.     xor al,    al        ; 16-bit count
  572.     sub ax,    EW_RBUF_NHDR    ; Less the four overhead bytes
  573.     sub cx,    ax        ; Move the rest in second part
  574.     push    cx        ; Save count of second part
  575.     mov cx,    ax        ; Count for first move
  576.     mov si,    EW_RBUF_NHDR    ; ds:si points at first byte to move
  577.     shr cx,    1        ; All above are even numbers, do words.
  578.     rep    movsw        ; Move first part of frame
  579.     mov ax,    mem_base    ; Paragraph of base of shared memory
  580.     mov ds,    ax        ; ..
  581.     mov si,    SM_RSTART_PG*256  ; Offset to start of first receive page
  582.     pop    cx        ; Bytes left to move
  583. rcopy_one_piece:
  584.     shr    cx,1        ; convert bytes to words
  585.     rep    movsw        ; word access desired for MC card
  586.     jnc    rcv_even    ; odd byte left over?
  587.     lodsw            ;   yes, word fetch
  588.     stosb            ;   and byte store
  589. rcv_even:
  590.     pop    si        ; Recover pointer to destination
  591.     pop    ds        ; Tell client it's his source
  592.     pop    cx        ; And it's this long
  593.     assume    ds:nothing
  594.     call    recv_copy    ; Give it to him
  595. rcv_no_copy:
  596.     push    cs        ; Put ds back in code space
  597.     pop    ds        ; ..
  598.     assume    ds:code
  599.     ret            ; That's it for rcv_frm
  600.  
  601.  
  602.     public    recv_exiting
  603. recv_exiting:
  604. ;called from the recv isr after interrupts have been acknowledged.
  605. ;Only ds and ax have been saved.
  606.     assume    ds:nothing
  607.     ret
  608.  
  609.  
  610. ;any code after this will not be kept after initialization.
  611. end_resident    label    byte
  612.  
  613.  
  614.     public    usage_msg
  615. usage_msg    db    "usage: WD8003E <packet_int_no> <int_level> <io_addr> <mem_base>",CR,LF,'$'
  616.  
  617.     public    copyright_msg
  618. copyright_msg    db    "Packet driver for Western Digital WD8003 E EBT and ET/A, version "
  619.         db    '0'+majver,".",'0'+version,CR,LF
  620.         db    "Portions Copyright 1988, Robert C. Clements, K1BC",CR,LF,'$'
  621.  
  622. no_board_msg:
  623.     db    "WD8003E apparently not present at this IO address.",CR,LF,'$'
  624. occupied_msg:
  625.     db    "Suggested WD8003E memory address already occupied",CR,LF,'$'
  626. int_no_name    db    "Interrupt number ",'$'
  627. io_addr_name    db    "I/O port ",'$'
  628. mem_base_name    db    "Memory address ",'$'
  629.  
  630.     extrn    set_recv_isr: near
  631.  
  632. ;enter with si -> argument string, di -> word to store.
  633. ;if there is no number, don't change the number.
  634.     extrn    get_number: near
  635.  
  636.     public    parse_args
  637. parse_args:
  638.     mov    di,offset int_no
  639.     mov    bx,offset int_no_name
  640.     call    get_number
  641.     mov    di,offset io_addr
  642.     mov    bx,offset io_addr_name
  643.     call    get_number
  644.     mov    di,offset mem_base
  645.     mov    bx,offset mem_base_name
  646.     call    get_number
  647.     ret
  648.  
  649.     extrn    etopen_diagn: byte
  650. addr_not_avail:
  651.     mov    dx,offset occupied_msg
  652.     mov    etopen_diagn,34
  653.     jmp    short error_wrt
  654. bad_cksum:
  655. no_memory:
  656.     mov    dx,offset no_board_msg
  657.     mov    etopen_diagn,37
  658. error_wrt:
  659.     mov    ah,9
  660.     int    21h
  661.     stc
  662.     ret
  663.  
  664.  
  665.     public    etopen
  666. etopen:                ; Initialize interface
  667.     loadport        ; First, pulse the board reset
  668.     setport    EW_CMD
  669.     mov al,    EW_RESET
  670.     out dx,    al        ; Turn on board reset bit
  671.     xor al,    al
  672.     out dx,    al        ; Turn off board reset bit
  673.     setport    EW_CCMD        ; DS8390 chip's command register
  674.     mov al,    EWC_NODMA+EWC_PAGE0    
  675.     out dx,    al        ; Switch to page zero
  676.     setport    EW0_ISR        ; Clear all interrupt flags
  677.     mov al,    0ffh        ; ..
  678.     out dx,    al        ; ..
  679. ; Copy our Ethernet address from PROM into the DS8390
  680. ; (No provision in driver spec for setting a false address.)
  681.     setport    EW_CCMD        ; Chip command register
  682.     mov al,    EWC_NODMA+EWC_PAGE1
  683.     out dx,    al        ; Switch to page one for writing eaddr
  684.     mov cl,    EADDR_LEN    ; Loop for six bytes
  685.     xor ch,    ch        ; Clear the index of bytes
  686.     xor bx,    bx        ; Clear the addr ROM checksum
  687. cpy_adr_loop:
  688.     loadport        ; Base of registers
  689.     setport    EW_SAPROM    ; Prom address
  690.     add dl,    ch        ; Plus which byte this is
  691.     in al,    dx        ; Get a byte of address
  692.     add    bl,al        ; Compute the checksum
  693.     add dl,    EW1_PHYS-EW_SAPROM ; Point at reg in chip
  694.     out dx,    al        ; Copy that byte
  695.     inc    ch        ; Step the index
  696.     dec    cl        ; Count bytes
  697.     jnz    cpy_adr_loop    ; Loop for six
  698.     loadport        ; Get last two bytes into cksum
  699.     setport    EW_SAPROM+EADDR_LEN
  700.     in al,    dx        ; Get seventh byte
  701.     add bl,    al        ; Add it in
  702.     inc    dx        ; Step to eighth byte
  703.     in al,    dx        ; Get last byte
  704.     add bl,    al        ; Final checksum
  705.     cmp bl, 0ffh        ; Correct?
  706.     jnz    bad_cksum    ; No, board is not happy
  707. ; Clear the multicast filter enables, we don't want any of them.
  708.     mov cl,    8        ; Eight bytes of multicast filter
  709.     xor al,    al        ; Zeros for filter
  710.     loadport        ; Base of multicast filter locations
  711.     setport    EW1_MULT    ; ..
  712. clr_mcast_l:
  713.     out dx,    al        ; Clear a byte
  714.     inc    dl        ; Step to next one
  715.     dec    cl        ; Count 8 filter locs
  716.     jnz    clr_mcast_l    ; ..    
  717.     loadport        ; Base of I/O regs
  718.     setport    EW_CCMD        ; Chip command register
  719.     mov al,    EWC_NODMA+EWC_PAGE0
  720.     out dx,    al        ; Back to page zero
  721.     setport    EW0_DCFG    ; Configure the fifo organization
  722.     mov al,    EWDCFG_BM8    ; Fifo threshold = 8 bytes
  723.     test    sys_features,microchannel
  724.     jz    bytemove
  725.     or    al,EWDCFG_WTS    ; word access for MC card
  726. bytemove:
  727.     out dx,    al
  728.     setport    EW0_RCNTLO    ; Clear the byte count registers
  729.     xor al,    al        ; ..
  730.     out dx,    al
  731.     setport    EW0_RCNTHI
  732.     out dx,    al        ; Clear high byte, too
  733.     setport    EW0_RXCR    ; Set receiver to monitor mode
  734.     mov al,    EWRXCR_MON
  735.     out dx,    al
  736.     setport    EW0_TXCR    ; Set transmitter mode to normal
  737.     xor al,    al
  738.     out dx,    al
  739. ; Check if the address range is availabe for us
  740.     mov    es,mem_base
  741.     mov    cx,2000h/2    ; 8 kbyte
  742.     mov    SM_RSTOP_PG,32
  743.     test    sys_features,microchannel
  744.     jz    just_8k
  745.     mov    cx,4000h/2    ; 16 bytes
  746.     mov    SM_RSTOP_PG,64
  747. just_8k:
  748.     xor    si,si
  749.     cld
  750. loop_avail:
  751.     mov    ax,es:[si]
  752.     cmp    ax,0ffffh        ; bus answer when noone is there
  753.     je    sofar_avail
  754.     jmp    addr_not_avail        ; we HAVE to have at least 8/16 kbyte
  755. sofar_avail:
  756.     inc    si
  757.     inc    si
  758.     loop    loop_avail
  759.  
  760.     test    sys_features,microchannel
  761.     jnz    not_32k
  762.     mov    cx,8000h/2 - 2000h/2    ; may be there is 32k available?
  763. loop_32k:
  764.     mov    ax,es:[si]
  765.     cmp    ax,0ffffh
  766.     jne    not_32k            ; no, then don't try it later either
  767.     inc    si
  768.     inc    si
  769.     loop    loop_32k
  770.     mov    SM_RSTOP_PG,128        ; yes, there is space for a WD8003EBT
  771. not_32k:
  772. ; Turn on the shared memory block
  773.     setport    EW_CMD        ; Point at board command register
  774.     mov ax,    mem_base    ; Find where shared memory will be mapped
  775.     mov al,    ah        ; Shift to right location
  776.     sar al,    1        ;  in the map control word
  777.     and al,    EW_MEM_MASK    ; Just these bits
  778.     or al,    EW_MEMEN    ; Command to turn on map
  779.     out dx,    al        ; Create that memory
  780.  
  781. ; Find how much memory this card has (without destroying other memory)
  782.     mov    si,ax            ; save bord command value
  783.     mov    es,mem_base
  784.     mov    bl,0FFh            ; first try 32 kbyte (WD8003EBT)
  785.     mov    bh,SM_RSTOP_PG        ;   or what is available
  786.     dec    bh
  787. memloop:
  788.     dec    bx            ; use even address
  789.     cli                ; disable interrupts
  790.     mov    cx,es:[bx]        ; save old memory contents
  791.     mov    word ptr es:[bx],05A5Ah    ; put testpattern
  792.     loadport
  793.     setport    EW_CCMD            ; drain the board bus for any
  794.     in    al,dx            ;   capacitive memory
  795.     cmp    word ptr es:[bx],05A5Ah    ; any real memory there?
  796.     jne    not_our_mem        ;   no
  797.     setport    EW_CMD            ;   yes
  798.     mov    ax,si
  799.     and    al,0FFh xor EW_MEMEN
  800.     out    dx,al            ; turn off our memory
  801.     jmp    short $+2
  802.     or    al,EW_MEMEN
  803.     cmp    word ptr es:[bx],05A5Ah    ; was it OUR memory?
  804.     out    dx,al
  805.     jmp    short $+2
  806.     mov    es:[bx],cx
  807.     sti
  808.     jne    our_mem            ;   yes, it wasn't there any more
  809. not_our_mem:                ;   no, it was still there
  810.     shr    bx,1            ; test if half as much memory
  811.     cmp    bx,1FFFh        ; down to 8 kbyte
  812.     jae    memloop
  813.     jmp    no_memory        ; no memory at address mem_base
  814. our_mem:                ; it IS our memory!
  815.     inc    bh
  816.     mov    SM_RSTOP_PG,bh        ; # of 256 byte ring bufs + 1
  817.  
  818.  
  819. ; Set up control of shared memory, buffer ring, etc.
  820.     setport    EW0_STARTPG    ; Set receiver's first buffer page
  821.     mov al,    SM_RSTART_PG
  822.     out dx,    al
  823.     setport    EW0_STOPPG    ;  and receiver's last buffer page + 1
  824.     mov al,    SM_RSTOP_PG
  825.     out dx,    al
  826.     setport    EW0_BOUNDARY    ; Set initial "last page we have emptied"
  827.     mov al,    SM_RSTART_PG
  828.     out dx,    al
  829.     setport    EW_CCMD        ; Switch to page one registers
  830.     mov al,    EWC_NODMA+EWC_PAGE1
  831.     out dx,    al
  832.     setport    EW1_CURPAG    ; Set current shared page for RX to work on
  833.     mov al,    SM_RSTART_PG+1
  834.     out dx,    al
  835.     setport    EW_CCMD        ; Switch back to page zero registers
  836.     mov al,    EWC_NODMA+EWC_PAGE0
  837.     out dx,    al
  838.     setport    EW0_IMR        ; Clear all interrupt enable flags
  839.     xor al,    al
  840.     out dx,    al
  841.     setport    EW0_ISR        ; Clear all interrupt assertion flags
  842.     mov al,    0ffh        ; again for safety before making the
  843.     out dx,    al        ; interrupt be enabled
  844.     call    set_recv_isr    ; Put ourselves in interrupt chain
  845.     loadport
  846.     setport    EW_CCMD        ; Now start the DS8390
  847.     mov al,    EWC_START+EWC_NODMA
  848.     out dx,    al        ; interrupt be enabled
  849.     setport    EW0_RXCR    ; Tell it to accept broadcasts
  850.     mov al,    EWRXCR_BCST
  851.     out dx,    al
  852.     setport    EW0_IMR        ; Tell card it can cause these interrupts
  853.     mov al,    EWISR_ALL
  854.     out dx,    al
  855.     mov    dx,offset end_resident
  856.     clc
  857.     ret
  858.  
  859. code    ends
  860.  
  861.     end
  862.